import React from "react";
import ReactDOM from 'react-dom';
import styles from './index.module.scss';
import {DraggableCore} from 'react-draggable';
import {NumberSize, Resizable} from "re-resizable";
import {MinusOutlined, CloseOutlined} from '@ant-design/icons';
import * as classnames from "classnames";

export interface IDragModalBoxProps {
  title: string,
  defaultPosition?: {
    left?: number,
    top?: number
  };
  defaultSize?: {
    width?: number,
    height?: number,
  };

  onResize?({width, height}: { width: number, height: number }): void,

  onClose?(): void,

  onMini?(isMini: boolean): void,

  children?: React.ReactNode,
}

interface IState {
  isMini: boolean;
}

/**
 *
 * @constructor
 */
class DraggableModalBox extends React.PureComponent<IDragModalBoxProps, IState> {
  static defaultProps = {
    defaultPosition: {
      left: 100,
      top: 60
    },
    defaultSize: {
      width: 500,
      height: 400,
    }
  }

  public resizable: any;
  public box: any;
  public ex: number;
  public ey: number;
  public windowWidth: number;
  public windowHeight: number;
  public position: IPosition;
  public size: NumberSize;
  public miniSize: NumberSize;
  public miniPosition: IPosition;
  public isDrag: boolean;
  public el: Element;
  public dlBox: any;


  constructor(props: IDragModalBoxProps) {
    super(props);
    this.resizable = null;
    this.box = null;
    this.dlBox = null;
    this.el = document.createElement('div');
    this.ex = 0;
    this.ey = 0;
    this.windowWidth = 0;
    this.windowHeight = 0;
    this.isDrag = false;

    this.position = Object.assign({
      left: 100,
      top: 60
    }, props.defaultPosition);

    this.size = Object.assign({
      width: 500,
      height: 400
    }, props.defaultSize);

    this.miniSize = {
      width: 180,
      height: 50
    };
    this.miniPosition = {
      left: 150,
      bottom: 0
    }
    this.state = {
      isMini: false,
    };

  }

  componentDidMount(): void {
    this.position = {
      left: this.box.offsetLeft,
      top: this.box.offsetTop
    };
    this.windowHeight = document.body.offsetHeight;
    this.windowWidth = document.body.offsetWidth;
    // 在内容前挂载header
    const dd = this.dlBox.getElementsByTagName('dd');
    this.dlBox.insertBefore(this.el, dd[0]);
  }

  // 正在拖拽
  onDrag = (e: MouseEvent, {x, y}: IPosition) => {

    this.position.left = parseInt(this.position.left + x - this.ex);
    this.position.top = parseInt(this.position.top + y - this.ey);
    if (this.position.left < 0) {
      this.position.left = 0
    }

    if (this.position.left > this.windowWidth - this.size.width) {
      this.position.left = this.windowWidth - this.size.width
    }
    if (this.position.top < 0) {
      this.position.top = 0
    }
    if (this.position.top > this.windowHeight - 50) {
      this.position.top = this.windowHeight - 50;
    }
    this.box.style.left = this.position.left + 'px';
    this.box.style.top = this.position.top + 'px';
  }

  onDragStart = (e: MouseEvent, {x, y, node}: IPosition) => {
    this.ex = x;
    this.ey = y;
    this.windowHeight = document.body.offsetHeight;
    this.windowWidth = document.body.offsetWidth;
    this.isDrag = true;
  }

  onDragStop = (e: MouseEvent, {x, y}: IPosition) => {
    this.isDrag = false;
  }

  onResize = (event, direction, elementRef, delta: NumberSize) => {
    const w = elementRef.offsetWidth;
    const h = elementRef.offsetHeight;
    this.box.style.width = w + 'px';
    this.box.style.height = h + 'px';

    if (typeof this.props.onResize === 'function') this.props.onResize({
      width: w,
      height: h
    });
  }

  onResizeStart = () => {
    this.windowHeight = document.body.offsetHeight;
    this.windowWidth = document.body.offsetWidth;
  }

  onResizeStop = (event: any, direction: string, elementRef: any, delta: NumberSize) => {
    const w = elementRef.offsetWidth;
    const h = elementRef.offsetHeight;
    try {
      this.resetModalStatus(w, h)
      // 是否最小化
      if (w <= this.miniSize.width && h <= this.miniSize.height) {
        this.setState({isMini: true})
      }
    } catch (e) {

    }
  }

  getResizeEnable() {
    return {
      right: true, bottom: true, bottomRight: true,
      top: false, left: false, topRight: false, bottomLeft: false, topLeft: false
    }
  }

  /**
   * 最小化
   */
  miniSizeAction = () => {
    this.setState({
      isMini: true
    }, () => {
      setTimeout(() => {
        const miniModalBox = document.querySelector('#miniModalBox');
        // this.dlBox.removeChild(this.el);
        if (miniModalBox) {
          miniModalBox.appendChild(this.el);
        }
      }, 10);
    })
  }

  /**
   * 重置大小
   */
  resetSizeAction = () => {
    this.setState({
      isMini: false
    }, () => {
      this.removeMiniBox();
      // 在内容前挂载header
      const dd = this.dlBox.getElementsByTagName('dd');
      this.dlBox.insertBefore(this.el, dd[0]);
    })
  }

  /**
   * 卸载最小化弹窗
   */
  removeMiniBox() {
    const miniModalBox = document.querySelector('#miniModalBox');
    try {
      if (miniModalBox) {
        miniModalBox.removeChild(this.el);
      }
    } catch (e) {
    }
  }

  onClose = () => {
    if (typeof this.props.onClose === 'function') this.props.onClose();
  }

  /**
   * 自动纠正模态框位置
   * @param w
   * @param h
   */
  resetModalStatus = (w: number, h: number) => {
    this.windowHeight = document.body.offsetHeight;
    this.windowWidth = document.body.offsetWidth;
    try {
      // 容器宽度限制,自适应
      if (w > this.windowWidth - 10) {
        this.position.left = 5;// 置左
        this.box.style.width = this.windowWidth - 10 + 'px';
        this.box.style.left = this.position.left + 'px';
        this.resizable.updateSize({width: this.windowWidth - 10, height: this.box.offsetHeight});
      }
      // 容器高度限制,自适应
      if (h > this.windowHeight - 10) {
        this.position.top = 5;// 置顶
        this.box.style.height = this.windowHeight - 10 + 'px';
        this.box.style.top = this.position.top + 'px';
        this.resizable.updateSize({width: this.box.offsetWidth, height: this.windowHeight - 10});
      }
    } catch (e) {

    }
  }

  clickTitle = (e: MouseEvent) => {
    e.preventDefault();
    this.resetModalStatus(this.size.width || 500, this.size.height || 400)
  }

  componentWillUnmount(): void {
    // 销毁弹窗
    this.removeMiniBox();
  }


  render(): React.ReactNode {

    return <div
      className={classnames(styles.modalBox, {
        [styles.mini]: this.state.isMini
      })}
      ref={e => this.box = e}
      style={{
        ...this.size,
        ...this.position
      }}
      >
      < Resizable
        defaultSize={{width: this.size.width, height: this.size.height}}
        className={styles.resizeBox}
        onResize={this.onResize}
        onResizeStop={this.onResizeStop}
        onResizeStart={this.onResizeStart}
        enable={this.getResizeEnable()}
        ref={e => this.resizable = e}
        minWidth={180}
        minHeight={50}
        >
        <DraggableCore
        handle={!this.state.isMini ? '.dragHandler': ''}
        onStop={this.onDragStop}
        onDrag={this.onDrag}
        onStart={this.onDragStart}
        >
        <dl className={styles.innerBox} ref={e => this.dlBox = e}>
      {
        ReactDOM.createPortal(<dt className={'header'}>

        <div
        className={classnames('title', 'dragHandler')}
        onClick={this.resetSizeAction}
        >
        {this.props.title}
        </div>
        <ul className={'actions'}>
        <li>
        {
          !this.state.isMini && <MinusOutlined
            onClick={this.miniSizeAction}
          />
        }
        </li>
        <li><CloseOutlined onClick={this.onClose}/></li>
        </ul>
        </dt>, this.el)
      }
        <dd className={styles.content}>{this.props.children}</dd>
        </dl>
        </DraggableCore>
        </Resizable>
        </div>
        }


        }

        export default DraggableModalBox
